package org.xxforest.game.core.utils;

public class XXPoint {

	public float x, y;
	
    public static XXPoint zero() {
        return new XXPoint(0, 0);
    }

    public XXPoint() {
        this(0, 0);
    }

    public static XXPoint create(float x, float y) {
        return new XXPoint(x, y);
    }

    private XXPoint(float x, float y) {
        this.x = x;
        this.y = y;
    }

    public static boolean equalToPoint(XXPoint p1, XXPoint p2) {
        return p1.x == p2.x && p1.y == p2.y;
    }


    /**
     * Returns opposite of point.
     *
     * @return xxpoint
     */
    public static XXPoint xxpNeg(final XXPoint v) {
        return create(-v.x, -v.y);
    }

    /**
     * Calculates sum of two points.
     *
     * @return xxpoint
     */
    public static XXPoint xxpAdd(final XXPoint v1, final XXPoint v2) {
        return create(v1.x + v2.x, v1.y + v2.y);
    }

    /**
     * Calculates difference of two points.
     *
     * @return xxpoint
     */
    public static XXPoint xxpSub(final XXPoint v1, final XXPoint v2) {
        return create(v1.x - v2.x, v1.y - v2.y);
    }

    /**
     * Returns point multiplied by given factor.
     *
     * @return xxpoint
     */
    public static XXPoint xxpMult(final XXPoint v, final float s) {
        return create(v.x * s, v.y * s);
    }

    /**
     * Calculates midpoint between two points.
     *
     * @return xxpoint
     */
    public static XXPoint xxpMidpoint(final XXPoint v1, final XXPoint v2) {
        return xxpMult(xxpAdd(v1, v2), 0.5f);
    }

    /**
     * Calculates dot product of two points.
     *
     * @return float
     */
    public static float xxpDot(final XXPoint v1, final XXPoint v2) {
        return v1.x * v2.x + v1.y * v2.y;
    }

    /**
     * Calculates cross product of two points.
     *
     * @return float
     */
    public static float xxpCross(final XXPoint v1, final XXPoint v2) {
        return v1.x * v2.y - v1.y * v2.x;
    }

    /**
     * Calculates perpendicular of v, rotated 90 degrees counter-clockwise -- cross(v, perp(v)) >= 0
     *
     * @return xxpoint
     */
    public static XXPoint xxpPerp(final XXPoint v) {
        return create(-v.y, v.x);
    }

    /**
     * Calculates perpendicular of v, rotated 90 degrees clockwise -- cross(v, rperp(v)) <= 0
     *
     * @return xxpoint
     */
    public static XXPoint xxpRPerp(final XXPoint v) {
        return create(v.y, -v.x);
    }

    /**
     * Calculates the projection of v1 over v2.
     *
     * @return xxpoint
     */
    public static XXPoint xxpProject(final XXPoint v1, final XXPoint v2) {
        return xxpMult(v2, xxpDot(v1, v2) / xxpDot(v2, v2));
    }

    /**
     * Rotates two points.
     *
     * @return xxpoint
     */
    public static XXPoint xxpRotate(final XXPoint v1, final XXPoint v2) {
        return create(v1.x * v2.x - v1.y * v2.y, v1.x * v2.y + v1.y * v2.x);
    }

    /**
     * Unrotates two points.
     *
     * @return xxpoint
     */
    public static XXPoint xxpUnrotate(final XXPoint v1, final XXPoint v2) {
        return create(v1.x * v2.x + v1.y * v2.y, v1.y * v2.x - v1.x * v2.y);
    }

    /**
     * Calculates the square length of a xxpoint (not calling sqrt() )
     *
     * @return float
     */
    public static float xxpLengthSQ(final XXPoint v) {
        return xxpDot(v, v);
    }

    /**
     * Calculates distance between point an origin
     *
     * @return float
     */
    public static float xxpLength(final XXPoint v) {
        return (float)Math.sqrt(xxpLengthSQ(v));
    }

    /**
     * Calculates the distance between two points
     *
     * @return float
     */
    public static float xxpDistance(final XXPoint v1, final XXPoint v2) {
        return xxpLength(xxpSub(v1, v2));
    }

    /**
     * Returns point multiplied to a length of 1.
     *
     * @return xxpoint
     */
    public static XXPoint xxpNormalize(final XXPoint v) {
        return xxpMult(v, 1.0f / xxpLength(v));
    }

    /**
     * Converts radians to a normalized vector.
     *
     * @return xxpoint
     */
    public static XXPoint xxpForAngle(final float a) {
        return create((float)Math.cos(a), (float)Math.sin(a));
    }

    /**
     * Converts a vector to radians.
     *
     * @return float
     */
    public static float xxpToAngle(final XXPoint v) {
        return (float) Math.atan2(v.y, v.x);
    }
    
    public static float xxpToDegree(final XXPoint v){
    	return (float) (180f/(Math.PI / xxpToAngle(v)));
    }
	
	public XXPoint alterX(float count){
		this.x += count ;
		return this ;
	}
	
	public XXPoint alterY(float count){
		this.y += count ;
		return this ;
	}
	
	public XXPoint add(XXPoint point){
		if(point != null){
			this.x += point.x ;
			this.y += point.y ;
		}
		return this ;
	}
	
	public XXPoint reduce(XXPoint point){
		if(point != null){
			this.x -= point.x ;
			this.y -= point.y ;
		}
		return this ;
	}
	
	public XXPoint copy(){
		return new XXPoint(x, y);
	}
	
	public float distance(XXPoint point){
		return distance(x, y, point.x, point.y);
	}
	
	public static float distance(float x1 ,float y1 , float x2 , float y2){
		float temp_A = x1-x2; 
		float temp_B = y1-y2; 
		return (float) Math.sqrt(temp_A*temp_A + temp_B*temp_B);
	}

	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append("XXPoint [x=");
		builder.append(x);
		builder.append(", y=");
		builder.append(y);
		builder.append("]");
		return builder.toString();
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + Float.floatToIntBits(x);
		result = prime * result + Float.floatToIntBits(y);
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		XXPoint other = (XXPoint) obj;
		if (Float.floatToIntBits(x) != Float.floatToIntBits(other.x))
			return false;
		if (Float.floatToIntBits(y) != Float.floatToIntBits(other.y))
			return false;
		return true;
	}
	
	
}
